package net

import (
	"bytes"
	"smart-flow/server/config"
	"smart-flow/server/logger"
	"smart-flow/server/utils"

	"go.uber.org/zap"

	cmap "github.com/orcaman/concurrent-map"
)

type ConsoleHandler struct {
	c *ConsoleClient
}

func (h *ConsoleHandler) OnConnected(ip string, port int) {
	logger.Logger.Info("[网络] 连接Console服务器成功, 正在登录服务器...", zap.String("ip", ip), zap.Int("port", port))
	h.c.LoginConsoleServer()
}

func (h *ConsoleHandler) OnDisconnected(ip string, port int) {
	logger.Logger.Info("[网络] 与Console服务器已断开", zap.String("ip", ip), zap.Int("port", port))
	h.c.LogoutConsoleServer()
}

func (h *ConsoleHandler) OnMessage(data *Package) {
	h.c.Invoke(data)
}

type ConsoleClient struct {
	client   *Client
	sessions cmap.ConcurrentMap
}

func ConsoleInstance(index int) *ConsoleClient {
	return consoleClients[index%clientCount]
}

func (c *ConsoleClient) ConnectConsoleServer(ip string, port int, autoReconnect bool) *ConsoleClient {
	c.sessions = cmap.New()
	c.client = new(Client)
	c.client.Connect(ip, port, autoReconnect, &ConsoleHandler{c})
	return c
}

func (c *ConsoleClient) DisConnectConsoleServer() {
	c.client.DisConnect()
}

func (c *ConsoleClient) LoginConsoleServer() {
	payload := utils.BufferPool.Get().(*bytes.Buffer)
	defer utils.Release(payload)
	if !Pack(uint32(config.CommonConsoleLogin), payload, []byte("gin")) {
		panic("构建数据包错误")
	}
	c.client.Send(payload)
}

func (c *ConsoleClient) LogoutConsoleServer() {
	logger.Logger.Info("[网络] 已从Console服务器登出")
}

func (c *ConsoleClient) Invoke(data *Package) {
	switch data.UiCmd {
	case config.CommonExecCmdRet:
		CommonExecCmdRet(data.ChBuff, c)
	case config.CommonAgentLoginReq:
		CommonAgentLoginReq(data.ChBuff, c)
	case config.CommonAgentLogoutReq:
		CommonAgentLogoutReq(data.ChBuff, c)
	case config.CommonAgentChannelReq:
		CommonAgentChannelReq(data.ChBuff, c)
	case config.CommonAgentChannelAck:
		CommonAgentChannelAck(data.ChBuff, c)
	case config.CommonAgentLost:
		return
	default:
		logger.Logger.Error("[网络] 未知指令", zap.Uint32("cmd", data.UiCmd))
		return
	}
}

func (c *ConsoleClient) Send(payload *bytes.Buffer) bool {
	return c.client.Send(payload)
}

func (c *ConsoleClient) GetSession(sessionId string) *Agent {
	val, exist := c.sessions.Get(sessionId)
	if !exist {
		return nil
	}
	return val.(*Agent)
}

func (c *ConsoleClient) DelSession(sessionId string) {
	c.sessions.Remove(sessionId)
}

func (c *ConsoleClient) AddSession(sessionId string, agent *Agent) {
	c.sessions.Set(sessionId, agent)
}
